home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CBASE102.ARJ / BTFIX.C < prev    next >
Text File  |  1991-09-23  |  7KB  |  299 lines

  1. /*    Copyright (c) 1989 Citadel    */
  2. /*       All Rights Reserved        */
  3.  
  4. /* #ident    "@(#)btfix.c    1.5 - 91/09/23" */
  5.  
  6. #include <ansi.h>
  7.  
  8. /* ansi headers */
  9. #include <errno.h>
  10. #ifdef AC_STDDEF
  11. #include <stddef.h>
  12. #endif
  13. #include <stdio.h>
  14. #ifdef AC_STDLIB
  15. #include <stdlib.h>
  16. #endif
  17. #ifdef AC_STRING
  18. #include <string.h>
  19. #endif
  20.  
  21. /*library headers */
  22. #include <blkio.h>
  23.  
  24. /* local headers */
  25. #include "btree_.h"
  26.  
  27. #undef min
  28. #define min(a,b)    ((a) < (b) ? (a) : (b))
  29.  
  30. /*man---------------------------------------------------------------------------
  31. NAME
  32.      btfix - fix a corrupt btree file
  33.  
  34. SYNOPSIS
  35.      int btfix(filename, m, keysize, fldc, fldv)
  36.      const char *filename;
  37.      int m;
  38.      size_t keysize;
  39.      int fldc;
  40.      const btfield_t fldv[];
  41.  
  42. DESCRIPTION
  43.      The btfix function reconstructs a corrupt btree.  The parameters
  44.      are the same as for btcreate.  It may be specified that the
  45.      degree of the btree and the key size be read from the header by
  46.      passing a value of zero for m and keysize, respectively.  These
  47.      parameters are provided for cases where the header is corrupt.
  48.  
  49.      btfix will fail if one or more of the following is true:
  50.  
  51.      [EINVAL]       filename is the NULL pointer.
  52.      [EINVAL]       fldc is less than 1.
  53.      [EINVAL]       fldv is the NULL pointer.
  54.      [EINVAL]       fldv contains an invalid field
  55.                     definition.
  56.      [ENOENT]       The named btree file does not exist.
  57.      [BTEEOF]       Incomplete file header.
  58.      [BTEMFILE]     Too many open btrees.  The maximum
  59.                     is defined as BTOPEN_MAX in btree.h.
  60.  
  61. SEE ALSO
  62.      btcreate.
  63.  
  64. DIAGNOSTICS
  65.      Upon successful completion, a value of 0 is returned.  Otherwise,
  66.      a value of -1 is returned, and errno set to indicate the error.
  67.  
  68. NOTES
  69.      It is recommended that a backup copy of the corrupted file be
  70.      made before calling a reconstruction routine such as btfix.
  71.  
  72.      If the btree contains only redundant data (i.e., an index), it is
  73.      better to rebuild it from scratch rather than attempt to fix it.
  74.  
  75.      btfix uses a temporary file to reconstruct the btree.  If
  76.      security is important, a call should be added to set the
  77.      permissions of the temporary file (e.g., chmod in UNIX) before
  78.      data is written to it.  This has not been included because such a
  79.      call is not portable.
  80.  
  81. ------------------------------------------------------------------------------*/
  82. #ifdef AC_PROTO
  83. int btfix(const char *filename, int m, size_t keysize, int fldc, const btfield_t fldv[])
  84. #else
  85. int btfix(filename, m, keysize, fldc, fldv)
  86. const char *filename;
  87. int m;
  88. size_t keysize;
  89. int fldc;
  90. const btfield_t fldv[];
  91. #endif
  92. {
  93.     int        terrno    = 0;        /* tmp errno */
  94.     bthdr_t        bthdr;            /* btree header */
  95.     char        tmpbtname[L_tmpnam + 1];/* temporary btree file name */
  96.     btree_t *    btp    = NULL;        /* btree */
  97.     btree_t        btree;            /* used for bt_blksize */
  98.     BLKFILE *    bp    = NULL;        /* block file */
  99.     btnode_t *    btnp    = NULL;        /* btree node */
  100.     bpos_t        bn    = 0;        /* block number */
  101.     int        k    = 0;        /* counter */
  102.     void *        buf    = NULL;
  103.  
  104.     /* validate arguments */
  105.     if (filename == NULL) {
  106.         errno = EINVAL;
  107.         return -1;
  108.     }
  109.  
  110.     /* open original btree file */
  111.     bp = bopen(filename, "r", sizeof(bthdr_t), (size_t)1, (size_t)0);
  112.     if (bp == NULL) {
  113.         if (errno != ENOENT) BTEPRINT;
  114.         return -1;
  115.     }
  116.     if (lockb(bp, B_RDLCK, (bpos_t)0, (bpos_t)0) == -1) {    /* read lock */
  117.         terrno = errno;
  118.         bclose(bp);
  119.         errno = terrno;
  120.         return -1;
  121.     }
  122.  
  123.     /* read header and set block size */
  124.     if (bgeth(bp, &bthdr) == -1) {
  125.         BTEPRINT;
  126.         if (errno == BEEOF) errno = BTEEOF;
  127.         terrno = errno;
  128.         bclose(bp);
  129.         errno = terrno;
  130.         return -1;
  131.     }
  132.     if (m == 0) {
  133.         m = bthdr.m;
  134.     }
  135.     if (keysize == 0) {
  136.         keysize = bthdr.keysize;
  137.     }
  138.     btree.bthdr.m = m;        /* set block size */
  139.     btree.bthdr.keysize = keysize;
  140.     if (bsetvbuf(bp, NULL, bt_blksize(&btree), (size_t)0) == -1) {
  141.         BTEPRINT;
  142.         terrno = errno;
  143.         bclose(bp);
  144.         errno = terrno;
  145.         return -1;
  146.     }
  147.  
  148.     /* create temporary btree */
  149.     tmpnam(tmpbtname);
  150.     if (btcreate(tmpbtname, m, keysize, fldc, fldv) == -1){
  151.         BTEPRINT;
  152.         terrno = errno;
  153.         bclose(bp);
  154.         errno = terrno;
  155.         return -1;
  156.     }
  157.     /*
  158.     If security is important, insert a call here
  159.     to set the permissions of file tmpbtname.  In UNIX, for
  160.     example,
  161.     #include <sys/types.h>
  162.     #include <sys/stat.h>
  163.     if (chmod(tmpbtname, S_IRUSR | S_IWUSR) == -1) {
  164.         BTEPRINT;
  165.         terrno = errno;
  166.         bclose(bp);
  167.         errno = terrno;
  168.         return -1;
  169.     }
  170.     */
  171.     btp = btopen(tmpbtname, "r+", fldc, fldv);
  172.     if (btp == NULL) {
  173.         BTEPRINT;
  174.         terrno = errno;
  175.         bclose(bp);
  176.         errno = terrno;
  177.         return -1;
  178.     }
  179.  
  180.     /* create in-core btree node */
  181.     btnp = bt_ndalloc(btp);
  182.     if (btnp == NULL) {
  183.         BTEPRINT;
  184.         terrno = errno;
  185.         bclose(bp);
  186.         btclose(btp);
  187.         errno = terrno;
  188.         return -1;
  189.     }
  190.  
  191.     /* create buffer for reading blocks */
  192.     buf = calloc((size_t)1, bt_blksize(&btree));
  193.     if (buf == NULL) {
  194.         BTEPRINT;
  195.         terrno = errno;
  196.         bclose(bp);
  197.         errno = terrno;
  198.         return -1;
  199.     }
  200.  
  201.     /* write lock temporary btree */
  202.     if (btlock(btp, BT_WRLCK) == -1) {
  203.         terrno = errno;
  204.         bclose(bp);
  205.         free(buf);
  206.         btclose(btp);
  207.         bt_ndfree(btnp);
  208.         errno = terrno;
  209.         return -1;
  210.     }
  211.  
  212.     /* main loop */
  213.     for (bn = 1; ; ++bn) {
  214.         /* get next node */
  215.         if (bgetb(bp, bn, buf) == -1) {
  216.             if (errno == BEEOF) {
  217.                 break;
  218.             }
  219.             BTEPRINT;
  220.             terrno = errno;
  221.             bclose(bp);
  222.             free(buf);
  223.             btclose(btp);
  224.             bt_ndfree(btnp);
  225.             errno = terrno;
  226.             return -1;
  227.         }
  228.  
  229.         /* convert file node to in-core format */
  230.         memcpy(btnp, buf, offsetof(btnode_t, keyv));
  231.         memcpy(btnp->keyv,
  232.             ((char *)buf + offsetof(btnode_t, keyv)),
  233.             ((btp->bthdr.m - 1) * btp->bthdr.keysize));
  234.         memcpy(btnp->childv,
  235.             ((char *)buf + offsetof(btnode_t, keyv) +
  236.                 ((btp->bthdr.m - 1) * btp->bthdr.keysize)),
  237.             (btp->bthdr.m * sizeof(*btnp->childv)));
  238.  
  239.         /* extract each key from node and insert in new btree */
  240.         if ((btnp->n != 0) && bt_ndleaf(btnp)) {
  241.             for (k = 1; k <= min(btnp->n, bt_ndmax(btp)); ++k) {
  242.                 if (btinsert(btp, bt_kykeyp(btp, btnp, k)) == -1) {
  243.                     if (errno != BTEDUP) {
  244.                         BTEPRINT;
  245.                         terrno = errno;
  246.                         bclose(bp);
  247.                         free(buf);
  248.                         btclose(btp);
  249.                         bt_ndfree(btnp);
  250.                         errno = terrno;
  251.                         return -1;
  252.                     }
  253.                 }
  254.             }
  255.         }
  256.     }
  257.  
  258.     /* free memory */
  259.     free(buf);
  260.     bt_ndfree(btnp);
  261.  
  262.     /* close and remove original btree file */
  263.     if (bclose(bp) == -1) {
  264.         BTEPRINT;
  265.         terrno = errno;
  266.         btclose(btp);
  267.         errno = terrno;
  268.         return -1;
  269.     }
  270.     if (remove(filename) != 0) {
  271.         BTEPRINT;
  272.         terrno = errno;
  273.         btclose(btp);
  274.         errno = terrno;
  275.         return -1;
  276.     }
  277.  
  278.     /* move temporary file to filename */
  279.     if (rename(tmpbtname, filename) != 0) {
  280.         BTEPRINT;
  281.         terrno = errno;
  282.         btclose(btp);
  283.         errno = terrno;
  284.         return -1;
  285.     }
  286.  
  287.     /* close and remove temporary file */
  288.     if (btclose(btp) == -1) {
  289.         BTEPRINT;
  290.         return -1;
  291.     }
  292.     if (remove(tmpbtname) != 0) {
  293.         BTEPRINT;
  294.         return -1;
  295.     }
  296.  
  297.     return 0;
  298. }
  299.